<?php

/**
 * Utilitaire de gestion des procédures
 */

require_once('commons_constantes.php');
require_once('commons_utils.php');
require_once('krn_dao.php');


//Définition des constantes d'accesseurs de la procédure
define('PROC_DEFINITION'			,0);
define('PROC_GET_NAME'				,1);
define('PROC_GET_DBNAME'			,2);
define('PROC_GET_IN_PARAM'			,3);
define('PROC_GET_OUT_PARAM'			,4);
define('PROC_GET_IN_OUT_PARAM'		,5);

//Constante dà exploiter pour la procédure
define('PROC_IN_PARAM_KEY'			,'IN');
define('PROC_OUT_PARAM_KEY'			,'OUT');


/**
 * Fonction de gestion des procédures. Définit une procédure et permet la récupération d'informations 
 * relatives à une procédure
 * @param string $getter
 * @param string $procCodeName
 * @param string $procName
 * @param string $dbName
 * @param array $inParams
 * @param array $outParam
 */
function procDefinition
		($getter
		,$procCodeName
		,$procName=null
		,$dbName=null
		,$inParams=array()
		,$outParam=null
		)
{
	static $procedures = null;
	switch($getter) {
		case PROC_DEFINITION :
			$procedures[$procCodeName] = array
										('procCode'		=> $procCodeName
										,'procName'		=> $procName
										,'dbName'		=> $dbName
										,'inParams'		=> $inParams
										,'outParam'		=> $outParam
										);
			return null;
			break;
			
		case PROC_GET_NAME :
			if (!is_null($procedures) && isset($procedures[$procCodeName])) {
				return $procedures[$procCodeName]['procName'];
			}
			return null;
			break;
			
		case PROC_GET_DBNAME :
			if (!is_null($procedures) && isset($procedures[$procCodeName])) {
				return $procedures[$procCodeName]['dbName'];
			}
			return null;
			break;
			
		case PROC_GET_IN_PARAM :
			if (!is_null($procedures) && isset($procedures[$procCodeName])) {
				return $procedures[$procCodeName]['inParams'];
			}
			return null;
			break;
			
		case PROC_GET_OUT_PARAM :
			if (!is_null($procedures) && isset($procedures[$procCodeName])) {
				return $procedures[$procCodeName]['outParam'];
			}
			return null;
			break;
			
		case PROC_GET_IN_OUT_PARAM :
			if (!is_null($procedures) && isset($procedures[$procCodeName])) {
				return array
					(PROC_IN_PARAM_KEY 		=> $procedures[$procCodeName]['inParams']
					,PROC_OUT_PARAM_KEY 	=> $procedures[$procCodeName]['outParam']
					);
			}
			return null;
			break;
			
		default :
			throw new Exception('Fonction procDefinition : accesseur ' . $getter . ' non défini', ERR_TECHNICAL);
	}
}

/**
 * Retourne le nom de la procédure de code $procCodeName ou null si le code n'est pas reconnu
 * @param string $procCodeName
 * @return string ou null
 */
function procGetName($procCodeName) {
	return procDefinition(PROC_GET_NAME,$procCodeName);
}

/**
 * Retourne le nom de la base de données de la procédure de code $procCodeName ou null si le code n'est pas reconnu
 * @param string $procCodeName
 * @return string ou null
 */
function procGetDBName($procCodeName) {
	return procDefinition(PROC_GET_DBNAME,$procCodeName);
}

/**
 * Retourne les paramètres d'entrée de la procédure de code $procCodeName ou null si le code n'est pas reconnu
 * @param string $procCodeName
 * @return array ou null
 */
function procGetInParams($procCodeName) {
	return procDefinition(PROC_GET_IN_PARAM,$procCodeName);
}

/**
 * Retourne le paramètre de sortie de la procédure de code $procCodeName ou null si le code n'est pas reconnu
 * @param string $procCodeName
 * @return string ou null
 */
function procGetOutParam($procCodeName) {
	return procDefinition(PROC_GET_OUT_PARAM,$procCodeName);
}

/**
 * Retourne les paramètres d'entrée et de sortie de la procédure de code $procCodeName ou null si le code n'est pas reconnu
 * @param string $procCodeName
 * @return array ou null
 */
function procGetInOutParams($procCodeName) {
	return procDefinition(PROC_GET_IN_OUT_PARAM,$procCodeName);
}

/**
 * Exécute la procédure de type Select et n'ayant pas de paramètre dont le code est $procCodeName
 * @param $procCodeName nom de code de la procédure à exécuter
 * @return null ou les résultats de la requête
 */
function procExecuteSelectTypeWithoutParams($procCodeName) {
	$procName = procGetName($procCodeName);
	if (is_null($procName)) {
		//Code de procédure inconnu, exception levée
		throw new Exception("Fonction procExecuteSelectTypeWithoutParams : code procédure $procCodeName inconnu", ERR_TECHNICAL);
	}
	
	$procDBName = procGetDBName($procCodeName);
	if (is_null($procDBName)) {
		//Code de procédure inconnu, exception levée
		throw new Exception("Fonction procExecuteSelectTypeWithoutParams : base de données de la procédure non définie.", ERR_TECHNICAL);
	}
	
	//Exécution de la procédure
	$query = "CALL $procName";
	$stmt = dbQueryExecution($procDBName
							 ,$query
							 );

	if (is_null($stmt)) {//La requête n'a pas pu s'exécuter'
		//trigger_error();
		throw new Exception('La requête "' . $query . '" n\'a pas pu s\'exécuter sur la base ' . $procDBName . '! ', ERR_TECHNICAL);
	}
	logDebug('Succès de l\'appel de procédure : ' . $query);
	return dbFetchAllFromStatement($stmt);
}

/**
 * Exécute la procédure de type Select et ayant des paramètres d'entrée dont le code est $procCodeName
 * @param $procCodeName nom de code de la procédure à exécuter
 * @param $inParams paramètres d'entrée
 * @return null ou les résultats de la requête
 */
function procExecuteSelectTypeWithParams($procCodeName, $inParams=array()) {
	return executeSelectTypeWithParams($procCodeName, $inParams, true);
}

/**
 * Exécute la procédure de type Select et ayant des paramètres d'entrée dont le code est $procCodeName
 * @param $funcCodeName nom de code de la fonction à exécuter
 * @param $inParams paramètres d'entrée
 * @return null ou les résultats de la requête
 */
function funcExecuteSelectTypeWithParams($funcCodeName, $inParams=array()) {
	return executeSelectTypeWithParams($funcCodeName, $inParams, false);
}

/**
 * Exécute une procédure ou une fonction de type Select et ayant des paramètres d'entrée dont le code est $procCodeName
 * @param $procCodeName nom de code de la procédure à exécuter
 * @param $inParams paramètres d'entrée
 * @param $isProc true si procédure / false si fonction
 * @return null ou les résultats de la requête
 */
function executeSelectTypeWithParams($procCodeName, $inParams=array(), $isProc) {
	$procName = procGetName($procCodeName);
	if (is_null($procName)) {
		//Code de procédure inconnu, exception levée
		throw new Exception("Fonction procExecuteSelectTypeWithoutParams : code procédure $procCodeName inconnu", ERR_TECHNICAL);
	}
	
	$procDBName = procGetDBName($procCodeName);
	if (is_null($procDBName)) {
		//Code de procédure inconnu, exception levée
		throw new Exception("Fonction procExecuteSelectTypeWithoutParams : base de données de la procédure non définie.", ERR_TECHNICAL);
	}
	
	$procInParams = procGetInParams($procCodeName);
	if (is_null($procInParams) || is_null($inParams)) {
		//Les paramètres d'entrée de la procédure ou ceux de la fonction sont nuls
		throw Exception("Fonction procExecuteSelectTypeWithParams : paramètres d'entrée ou en arguments nuls.", ERR_TECHNICAL);
	} elseif (count($procInParams) != count($inParams)) {
		//Les paramètres d'entrée de définition de la procédure et ceux donnés en entrée ne correspondent pas
		throw Exception("Fonction procExecuteSelectTypeWithParams : paramètres d'entrée incohérents.", ERR_TECHNICAL);
	}
	
	//Nombre d'éléments des paramètress d'entrée
	$nbInParams = count($inParams);
	$inArgs = '';
	for ($i=0; $i<$nbInParams; $i++) {
		if ($inArgs != '') {
			$inArgs .= ',';
		}
		$inArgs .= '?';
	}
	
	//Exécution de la procédure
	$query = 'SELECT ';
	if ($isProc) {
		$query = 'CALL ';
	}
	$query .= "$procName($inArgs)";
	$stmt = dbQueryExecution($procDBName
							 ,$query
							 ,$inParams
							 );

	if (is_null($stmt)) {//La requête n'a pas pu s'exécuter'
		//trigger_error();
		throw new Exception('La requête "' . $query . '" n\'a pas pu s\'exécuter sur la base ' . $procDBName . '! ', ERR_TECHNICAL);
	}
	logDebug('Succès de l\'appel de procédure : ' . $query);
	return dbFetchAllFromStatement($stmt);
}
